package 遍历器;

import 抽象语法树节点.*;
import 抽象语法树节点.表达式类.加法表达式;
import 抽象语法树节点.表达式类.变量引用表达式;
import 抽象语法树节点.表达式类.整数字面量表达式;
import 抽象语法树节点.表达式类.方法调用表达式;
import 抽象语法树节点.语句类.变量定义语句;
import 抽象语法树节点.语句类.块语句;
import 抽象语法树节点.语句类.赋值语句;
import 抽象语法树节点.语句类.返回语句;

public class 抽象语法树基础遍历器 {

    public 抽象语法树基础遍历器(抽象语法树基础监听器 监听器) {
        this.监听器 = 监听器;
    }

    private final 抽象语法树基础监听器 监听器;

    public void 遍历(抽象语法树 节点) {
        监听器.进入抽象语法树(节点);

        if (节点 instanceof 编译单元) {
            遍历((编译单元) 节点);
        } else if (节点 instanceof 方法参数) {
            遍历((方法参数) 节点);
        } else if (节点 instanceof 方法定义) {
            遍历((方法定义) 节点);
        } else if (节点 instanceof 类型) {
            遍历((类型) 节点);
        } else if (节点 instanceof 表达式) {
            遍历((表达式) 节点);
        } else if (节点 instanceof 表达式列表) {
            遍历((表达式列表) 节点);
        } else if (节点 instanceof 语句) {
            遍历((语句) 节点);
        }

        监听器.退出抽象语法树(节点);
    }

    private void 遍历(编译单元 节点) {
        监听器.进入编译单元(节点);

        for (var i = 0; i < 节点.子节点.length; i++) {
            遍历(节点.子节点[i]);
        }

        监听器.退出编译单元(节点);
    }

    private void 遍历(方法参数 节点) {
        监听器.进入方法参数(节点);
        遍历(节点.返回值类型);
        监听器.退出方法参数(节点);
    }

    private void 遍历(方法定义 节点) {
        监听器.进入方法定义(节点);

        遍历(节点.返回值类型);
        if (节点.参数列表 != null) {
            for (var i = 0; i < 节点.参数列表.length; i++) {
                遍历(节点.参数列表[i]);
            }
        }

        遍历(节点.语句块);

        监听器.退出方法定义(节点);
    }

    private void 遍历(类型 节点) {
        监听器.进入类型(节点);
        监听器.退出类型(节点);
    }

    private void 遍历(表达式 节点) {
        监听器.进入表达式(节点);

        if (节点 instanceof 加法表达式) {
            遍历((加法表达式) 节点);
        } else if (节点 instanceof 变量引用表达式) {
            遍历((变量引用表达式) 节点);
        } else if (节点 instanceof 整数字面量表达式) {
            遍历((整数字面量表达式) 节点);
        } else if (节点 instanceof 方法调用表达式) {
            遍历((方法调用表达式) 节点);
        }

        监听器.退出表达式(节点);
    }

    private void 遍历(表达式列表 节点) {
        监听器.进入表达式列表(节点);

        for (var i = 0; i < 节点.表达式组.length; i++) {
            遍历(节点.表达式组[i]);
        }

        监听器.退出表达式列表(节点);
    }

    private void 遍历(语句 节点) {
        监听器.进入语句(节点);

        if (节点 instanceof 变量定义语句) {
            遍历((变量定义语句) 节点);
        } else if (节点 instanceof 块语句) {
            遍历((块语句) 节点);
        } else if (节点 instanceof 赋值语句) {
            遍历((赋值语句) 节点);
        } else if (节点 instanceof 返回语句) {
            遍历((返回语句) 节点);
        }

        监听器.退出语句(节点);
    }

    // 语句

    private void 遍历(变量定义语句 节点) {
        监听器.进入变量定义语句(节点);

        遍历(节点.类型);
        遍历(节点.初始化表达式);

        监听器.退出变量定义语句(节点);
    }

    private void 遍历(块语句 节点) {
        监听器.进入块语句(节点);

        for (var i = 0; i < 节点.语句.length; i++) {
            遍历(节点.语句[i]);
        }

        监听器.退出块语句(节点);
    }

    private void 遍历(赋值语句 节点) {
        监听器.进入赋值语句(节点);

        遍历(节点.左值);
        遍历(节点.右值);

        监听器.退出赋值语句(节点);
    }

    private void 遍历(返回语句 节点) {
        监听器.进入返回语句(节点);

        遍历(节点.返回值);

        监听器.退出返回语句(节点);
    }


    // 表达式

    private void 遍历(加法表达式 节点) {
        监听器.进入加法表达式(节点);

        for (var i = 0; i < 节点.参数列表.length; i++) {
            遍历(节点.参数列表[i]);
        }

        监听器.退出加法表达式(节点);
    }

    private void 遍历(变量引用表达式 节点) {
        监听器.进入变量引用表达式(节点);
        监听器.退出变量引用表达式(节点);
    }

    private void 遍历(整数字面量表达式 节点) {
        监听器.进入整数字面量表达式(节点);
        监听器.退出整数字面量表达式(节点);
    }

    private void 遍历(方法调用表达式 节点) {
        监听器.进入方法调用表达式(节点);
        遍历(节点.参数列表);
        监听器.退出方法调用表达式(节点);
    }
}
